/**
 * Copyright (c) Tiny Technologies, Inc. All rights reserved.
 * Licensed under the LGPL or a commercial license.
 * For LGPL see License.txt in the project root for license information.
 * For commercial licenses see https://www.tiny.cloud/
 *
 * Version: 5.10.0 (2021-10-11)
 */
(function() {
  'use strict'

  var global$3 = tinymce.util.Tools.resolve('tinymce.PluginManager')

  var global$2 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils')

  var global$1 = tinymce.util.Tools.resolve('tinymce.util.I18n')

  var global = tinymce.util.Tools.resolve('tinymce.util.Tools')

  var getTocClass = function(editor) {
    return editor.getParam('toc_class', 'mce-toc')
  }
  var getTocHeader = function(editor) {
    var tagName = editor.getParam('toc_header', 'h2')
    return /^h[1-6]$/.test(tagName) ? tagName : 'h2'
  }
  var getTocDepth = function(editor) {
    var depth = parseInt(editor.getParam('toc_depth', '3'), 10)
    return depth >= 1 && depth <= 9 ? depth : 3
  }

  var create = function(prefix) {
    var counter = 0
    return function() {
      var guid = new Date().getTime().toString(32)
      return prefix + guid + (counter++).toString(32)
    }
  }

  var tocId = create('mcetoc_')
  var generateSelector = function(depth) {
    var i
    var selector = []
    for (i = 1;i <= depth;i++) {
      selector.push('h' + i)
    }
    return selector.join(',')
  }
  var hasHeaders = function(editor) {
    return readHeaders(editor).length > 0
  }
  var readHeaders = function(editor) {
    var tocClass = getTocClass(editor)
    var headerTag = getTocHeader(editor)
    var selector = generateSelector(getTocDepth(editor))
    var headers = editor.$(selector)
    if (headers.length && /^h[1-9]$/i.test(headerTag)) {
      headers = headers.filter(function(i, el) {
        return !editor.dom.hasClass(el.parentNode, tocClass)
      })
    }
    return global.map(headers, function(h) {
      var id = h.id
      return {
        id: id || tocId(),
        level: parseInt(h.nodeName.replace(/^H/i, ''), 10),
        title: editor.$.text(h),
        element: h
      }
    })
  }
  var getMinLevel = function(headers) {
    var minLevel = 9
    for (var i = 0;i < headers.length;i++) {
      if (headers[i].level < minLevel) {
        minLevel = headers[i].level
      }
      if (minLevel === 1) {
        return minLevel
      }
    }
    return minLevel
  }
  var generateTitle = function(tag, title) {
    var openTag = '<' + tag + ' contenteditable="true">'
    var closeTag = '</' + tag + '>'
    return openTag + global$2.DOM.encode(title) + closeTag
  }
  var generateTocHtml = function(editor) {
    var html = generateTocContentHtml(editor)
    return '<div class="' + editor.dom.encode(getTocClass(editor)) + '" contenteditable="false">' + html + '</div>'
  }
  var generateTocContentHtml = function(editor) {
    var html = ''
    var headers = readHeaders(editor)
    var prevLevel = getMinLevel(headers) - 1
    if (!headers.length) {
      return ''
    }
    html += generateTitle(getTocHeader(editor), global$1.translate('Table of Contents'))
    for (var i = 0;i < headers.length;i++) {
      var h = headers[i]
      h.element.id = h.id
      var nextLevel = headers[i + 1] && headers[i + 1].level
      if (prevLevel === h.level) {
        html += '<li>'
      } else {
        for (var ii = prevLevel;ii < h.level;ii++) {
          html += '<ul><li>'
        }
      }
      html += '<a href="#' + h.id + '">' + h.title + '</a>'
      if (nextLevel === h.level || !nextLevel) {
        html += '</li>'
        if (!nextLevel) {
          html += '</ul>'
        }
      } else {
        for (var ii = h.level;ii > nextLevel;ii--) {
          html += '</li></ul><li>'
        }
      }
      prevLevel = h.level
    }
    return html
  }
  var isEmptyOrOffscreen = function(editor, nodes) {
    return !nodes.length || editor.dom.getParents(nodes[0], '.mce-offscreen-selection').length > 0
  }
  var insertToc = function(editor) {
    var tocClass = getTocClass(editor)
    var $tocElm = editor.$('.' + tocClass)
    if (isEmptyOrOffscreen(editor, $tocElm)) {
      editor.insertContent(generateTocHtml(editor))
    } else {
      updateToc(editor)
    }
  }
  var updateToc = function(editor) {
    var tocClass = getTocClass(editor)
    var $tocElm = editor.$('.' + tocClass)
    if ($tocElm.length) {
      editor.undoManager.transact(function() {
        $tocElm.html(generateTocContentHtml(editor))
      })
    }
  }

  var register$1 = function(editor) {
    editor.addCommand('mceInsertToc', function() {
      insertToc(editor)
    })
    editor.addCommand('mceUpdateToc', function() {
      updateToc(editor)
    })
  }

  var setup = function(editor) {
    var $ = editor.$;var tocClass = getTocClass(editor)
    editor.on('PreProcess', function(e) {
      var $tocElm = $('.' + tocClass, e.node)
      if ($tocElm.length) {
        $tocElm.removeAttr('contentEditable')
        $tocElm.find('[contenteditable]').removeAttr('contentEditable')
      }
    })
    editor.on('SetContent', function() {
      var $tocElm = $('.' + tocClass)
      if ($tocElm.length) {
        $tocElm.attr('contentEditable', false)
        $tocElm.children(':first-child').attr('contentEditable', true)
      }
    })
  }

  var toggleState = function(editor) {
    return function(api) {
      var toggleDisabledState = function() {
        return api.setDisabled(editor.mode.isReadOnly() || !hasHeaders(editor))
      }
      toggleDisabledState()
      editor.on('LoadContent SetContent change', toggleDisabledState)
      return function() {
        return editor.on('LoadContent SetContent change', toggleDisabledState)
      }
    }
  }
  var isToc = function(editor) {
    return function(elm) {
      return elm && editor.dom.is(elm, '.' + getTocClass(editor)) && editor.getBody().contains(elm)
    }
  }
  var register = function(editor) {
    var insertTocAction = function() {
      return editor.execCommand('mceInsertToc')
    }
    editor.ui.registry.addButton('toc', {
      icon: 'toc',
      tooltip: 'Table of contents',
      onAction: insertTocAction,
      onSetup: toggleState(editor)
    })
    editor.ui.registry.addButton('tocupdate', {
      icon: 'reload',
      tooltip: 'Update',
      onAction: function() {
        return editor.execCommand('mceUpdateToc')
      }
    })
    editor.ui.registry.addMenuItem('toc', {
      icon: 'toc',
      text: 'Table of contents',
      onAction: insertTocAction,
      onSetup: toggleState(editor)
    })
    editor.ui.registry.addContextToolbar('toc', {
      items: 'tocupdate',
      predicate: isToc(editor),
      scope: 'node',
      position: 'node'
    })
  }

  function Plugin() {
    global$3.add('toc', function(editor) {
      register$1(editor)
      register(editor)
      setup(editor)
    })
  }

  Plugin()
}())
